#include "graphicslayoutiterator.h"

#include <QGraphicsLayout>

bool GraphicsLayoutIterator::operator++()
{
    if(!item) { return false; }
    
    int i;
    QGraphicsLayout * layout = getParentLayoutAndIndex(item, i);
    if(!layout) { return false; }
    
    Q_FOREVER {
        // Get next item
        ++i;
        if(i >= layout->count())
            break;
        QGraphicsLayoutItem * tmp = layout->itemAt(i);
        
        // Check for child layouts
        QGraphicsLayout * childLayout = hasChildren(tmp);
        if(childLayout) {
            tmp = childLayout->itemAt(0);
            if(isFocusable(tmp)) {
                item = tmp;
                return true;
            } else {
                // recurse
                GraphicsLayoutIterator it(tmp, isFocusable);
                ++it;
                if(it.item != tmp) {
                    item = it.item;
                    return true;
                    }
            }
            return false;
        }
        
        // Check if focusable
        if(isFocusable(tmp)) {
            item = tmp;
            return true;
        }
    }
    
    // recurse upwards
    GraphicsLayoutIterator it(layout, isFocusable);
    if(++it) {
        item = it.item;
        return true;
    }
        
    return false;
}

bool GraphicsLayoutIterator::operator--()
{
    if(!item) { return false; }
    
    int i;
    QGraphicsLayout * layout = getParentLayoutAndIndex(item, i);
    if(!layout) { return false; }
    
    Q_FOREVER {
        // Get next item
        --i;
        if(i < 0)
            break;
        QGraphicsLayoutItem * tmp = layout->itemAt(i);
        
        // Check for child layouts
        QGraphicsLayout * childLayout = hasChildren(tmp);
        if(childLayout) {
            tmp = childLayout->itemAt(childLayout->count() - 1);
            if(isFocusable(tmp)) {
                item = tmp;
                return true;
            } else {
                // recurse
                GraphicsLayoutIterator it(tmp, isFocusable);
                if(--it) {
                    item = it.item;
                    return true;
                }
            }
            return false;
        }
        
        // Check if focusable
        if(isFocusable(tmp)) {
            item = tmp;
            return true;
        }
    }
    
    // recurse upwards
    GraphicsLayoutIterator it(layout, isFocusable);
    if(--it) {
        item = it.item;
        return true;
    }
        
    return false;
}

GraphicsLayoutIterator::operator bool ()
{
    return item && item->graphicsItem() != 0;
}

GraphicsLayoutIterator::operator QGraphicsItem * ()
{
    return item ? item->graphicsItem() : 0;
}

QGraphicsItem & GraphicsLayoutIterator::operator*()
{
    return *item->graphicsItem();
}

QGraphicsItem * GraphicsLayoutIterator::operator->()
{
    return item->graphicsItem();
}

QGraphicsLayout * GraphicsLayoutIterator::getParentLayoutAndIndex(QGraphicsLayoutItem * item, int & index)
{
    if(!item) { return 0; }
        
    QGraphicsLayoutItem * parent = item->parentLayoutItem();
    if(!parent || !parent->isLayout()) { return 0; }
    
    QGraphicsLayout * layout = static_cast<QGraphicsLayout *>(parent); 
    index = indexOfItemInLayout(*layout);
    if(index < 0) { return 0; }
    
    return layout;
}

int GraphicsLayoutIterator::indexOfItemInLayout(QGraphicsLayout & layout)
{
    for(int i = 0; i < layout.count(); ++i) {
        if(layout.itemAt(i) == item) { return i; }
    }
    return -1;
}

QGraphicsLayout * GraphicsLayoutIterator::hasChildren(QGraphicsLayoutItem * item)
{
    if(!item->isLayout()) { return 0; }
    QGraphicsLayout * layout = static_cast<QGraphicsLayout *> (item);
    if(!layout->count()) { return 0; }
    return layout;
}
